package com.idanchuang.support.etcache.support.jetcache;

import com.alicp.jetcache.*;
import com.alicp.jetcache.external.AbstractExternalCache;
import com.idanchuang.support.etcache.Cache;
import com.idanchuang.support.etcache.local.LocalCacheConfig;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * ExternalCache 的 EtCache实现
 *
 * @author yjy
 */
public class EtCacheJetCache<K, V> extends AbstractExternalCache<K, V> {

    private final EtCacheExternalCacheConfig<K, V> config;
    private final Cache<K, V> cache;

    public EtCacheJetCache(EtCacheExternalCacheConfig<K, V> config) {
        super(config);
        this.config = config;
        String cacheName = "JetEtCache";
        LocalCacheConfig localCacheConfig = new LocalCacheConfig(cacheName, config.getManager().getPressureChecker());
        localCacheConfig.setExpire(config.getExpireAfterWriteInMillis());
        localCacheConfig.setTimeUnit(TimeUnit.MILLISECONDS);
        this.cache = config.getManager().getCache(cacheName, localCacheConfig);
    }

    @Override
    public <T> T unwrap(Class<T> clazz) {
        if (clazz.equals(Cache.class)) {
            return (T) cache;
        }
        throw new IllegalArgumentException(clazz.getName());
    }

    @Override
    public CacheConfig<K, V> config() {
        return config;
    }

    @Override
    protected CacheGetResult<V> do_GET(K key) {
        V v = cache.get(key);
        if (v == null) {
            return CacheGetResult.NOT_EXISTS_WITHOUT_MSG;
        }
        CacheValueHolder<V> holder = new CacheValueHolder<>(v, config.getExpireAfterWriteInMillis());
        return new CacheGetResult<>(CacheResultCode.SUCCESS, null, holder);
    }

    @Override
    protected MultiGetResult<K, V> do_GET_ALL(Set<? extends K> keys) {
        Set<K> set = new HashSet<>(keys);
        Map<K, V> map = cache.getAll(set);
        Map<K, CacheGetResult<V>> resultMap = new HashMap<>();
        map.forEach((k, v) -> {
            if (v == null) {
                resultMap.put(k, CacheGetResult.NOT_EXISTS_WITHOUT_MSG);
            } else {
                CacheValueHolder<V> holder = new CacheValueHolder<>(v, config.getExpireAfterWriteInMillis());
                resultMap.put(k, new CacheGetResult<>(CacheResultCode.SUCCESS, null, holder));
            }
        });
        return new MultiGetResult<>(CacheResultCode.SUCCESS, null, resultMap);
    }

    @Override
    protected CacheResult do_PUT(K key, V value, long expireAfterWrite, TimeUnit timeUnit) {
        cache.set(key, value, expireAfterWrite, timeUnit);
        return CacheResult.SUCCESS_WITHOUT_MSG;
    }

    @Override
    protected CacheResult do_PUT_ALL(Map<? extends K, ? extends V> map, long expireAfterWrite, TimeUnit timeUnit) {
        Map<K, V> newMap = new HashMap<>(map);
        cache.setAll(newMap, expireAfterWrite, timeUnit);
        return CacheResult.SUCCESS_WITHOUT_MSG;
    }

    @Override
    protected CacheResult do_REMOVE(K key) {
        cache.remove(key);
        return CacheResult.SUCCESS_WITHOUT_MSG;
    }

    @Override
    protected CacheResult do_REMOVE_ALL(Set<? extends K> keys) {
        Set<K> set = new HashSet<>(keys);
        cache.removeAll(set);
        return CacheResult.SUCCESS_WITHOUT_MSG;
    }

    @Override
    protected CacheResult do_PUT_IF_ABSENT(K key, V value, long expireAfterWrite, TimeUnit timeUnit) {
        V v = cache.get(key);
        if (v == null) {
            cache.set(key, value, expireAfterWrite, timeUnit);
        }
        return CacheResult.SUCCESS_WITHOUT_MSG;
    }
}
